package business.global.pk.ddz;

import business.ddz.c2s.cclass.*;
import business.ddz.c2s.cclass.DDZ_define.DDZ_ConfirmTheLandlord;
import business.ddz.c2s.cclass.DDZ_define.DDZ_GameStatus;
import business.ddz.c2s.iclass.*;
import business.global.room.base.AbsRoomPos;
import business.global.room.base.AbsRoomSet;
import business.global.room.base.RoomPlayBack;
import business.player.Player;
import business.player.PlayerMgr;
import business.player.Robot.RobotMgr;
import business.player.feature.PlayerCurrency;
import cenum.PrizeType;
import cenum.RoomTypeEnum;
import cenum.room.TrusteeshipState;
import com.ddm.server.common.utils.CommMath;
import com.ddm.server.common.utils.CommTime;
import com.ddm.server.common.utils.Random;
import com.ddm.server.websocket.def.ErrorCode;
import com.ddm.server.websocket.handler.requset.WebSocketRequest;
import com.google.gson.Gson;
import core.db.entity.clarkGame.GameSetBO;
import core.db.service.clarkGame.GameSetBOService;
import core.ioc.ContainerMgr;
import jsproto.c2s.cclass.BaseSendMsg;
import jsproto.c2s.cclass.pk.BasePocker;
import jsproto.c2s.cclass.pk.BasePockerLogic;
import jsproto.c2s.cclass.playback.PlayBackData;
import jsproto.c2s.cclass.room.RoomPosInfo;
import org.apache.commons.collections.CollectionUtils;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;


/**
 * 资阳跑得快一局游戏逻辑
 */
public class DDZRoomSet extends AbsRoomSet {
    /**
     * 每个位置信息
     */
    protected Map<Integer, DDZSetPos> posDict = null;
    public DDZRoom room;
    public long startMS = 0;
    protected DDZ_GameStatus status = DDZ_GameStatus.DDZ_GAME_STATUS_SENDCARD;
    public DDZSetCard setCard = null;
    public DDZRoom_SetEnd setEnd = new DDZRoom_SetEnd();
    public GameSetBO bo = null;
    protected int m_OpPos = 0;                //当前操作位置
    public ArrayList<Integer> pointList;        //得分
    protected RoomPlayBack roomPlayBack;        //回放
    protected HashMap<Integer, List<Integer>> hMap = new HashMap<Integer, List<Integer>>();
    public DDZRoomSetRound curRound = null;
    public List<DDZRoomSetRound> historyRound = new ArrayList<>();
    public List<Integer> totalPointResult = new ArrayList<>();//总分
    public ArrayList<Double> sportsPointList = null;
    protected int landowner = -1; // 地主
    protected ArrayList<Integer> addDoubleList; // 加倍 -1:没有操作 0:不加倍 1:加倍
    protected ArrayList<Integer> openCardList; // 是否明牌 -1:没有操作 0:不明牌 1:明牌
    protected ArrayList<Integer> openMultipleCard; // 明牌加倍
    public ArrayList<Integer> holeCards; // 底牌
    protected ArrayList<Integer> hogList; // 抢庄 -1:没有操作 0:不抢庄 1:抢庄
    protected ArrayList<Integer> robCloseList; // 春天 -1:反春天 0:没有春天或者饭反春天 1:春天
    protected int hogScore = 0; // 抢地主倍数，结算用
    protected int hogCount = 0; // 叫地主抢地主次数
    protected int lastHogPos = -1; // 最后抢地主的人
    protected int roomDouble = 1;//房间倍数=底牌倍数*所有炸弹倍数
    protected boolean bFirstOp = true;//是否首出
    protected int winPos = -1; //赢家
    protected int twoValue = 15; //2
    protected int nowHog = 0; //当前叫分值

    public DDZRoomSet(DDZRoom room) {
        super(room.getCurSetID());
        this.room = room;
        this.pointList = new ArrayList<>(Collections.nCopies(this.room.getPlayerNum(), 0));
        this.openCardList = new ArrayList<>(Collections.nCopies(this.room.getPlayerNum(), -1));
        this.openMultipleCard = new ArrayList<>(Collections.nCopies(this.room.getPlayerNum(), 0));
        this.hogList = new ArrayList<>(Collections.nCopies(this.room.getPlayerNum(), -1));
        this.addDoubleList = new ArrayList<>(Collections.nCopies(this.room.getPlayerNum(), -1));
        this.robCloseList = new ArrayList<>(Collections.nCopies(this.room.getPlayerNum(), 0));
        this.holeCards = new ArrayList<>();
        this.initSportsPointList();
        this.addGameConfig();
        this.recordRoomPosPointBeginStart();
        this.setJoinPlayer();
        if (getSetID() == 1 && room.isCanOpenCard() && !room.isOpenStartGame()) {
            this.startMS = CommTime.nowMS();
            onChangeStatus(DDZ_GameStatus.DDZ_GAME_STATUS_OPENCARD);
            room.setOpenStartGame(true);
        } else {
            this.startSet();
            onChangeStatus(DDZ_GameStatus.DDZ_GAME_STATUS_SENDCARD);
        }
    }

    /**
     * 初始化位置
     */
    protected void initSetPos() {
        this.posDict = new ConcurrentHashMap<>(this.room.getPlayerNum());
        for (int posId = 0; posId < this.room.getPlayerNum(); posId++) {
            this.getPosDict().put(posId, new DDZSetPos(posId, this.room.getRoomPosMgr().getPosByPosID(posId), this));
        }
    }

    public Map<Integer, DDZSetPos> getPosDict() {
        return posDict;
    }

    /**
     * 标识Id
     *
     * @return
     */
    @Override
    public int getTabId() {
        return this.room.getTabId();
    }

    private void setJoinPlayer() {
        //设置参与游戏的玩家
        for (AbsRoomPos pos : this.room.getRoomPosMgr().getPosList()) {
            DDZRoomPos roomPos = (DDZRoomPos) pos;
            if ((pos.isReady() && this.room.getCurSetID() == 1) || (this.room.getCurSetID() > 1 && pos.getPid() != 0)) {
                roomPos.setPlayTheGame(true);
            }
        }
        // 洗底牌
        this.setCard = new DDZSetCard(this.room);
    }

    private void initSportsPointList() {
        if (RoomTypeEnum.UNION.equals(this.room.getRoomTypeEnum())) {
            this.sportsPointList = new ArrayList<>(Collections.nCopies(this.room.getPlayerNum(), 0D));
        }
    }

    /**
     * 回放记录添加游戏配置
     */
    @Override
    public void addGameConfig() {
        this.getRoomPlayBack().addPlaybackList(SDDZ_Config.make(room.getCfg(), this.room.getRoomTyepImpl().getRoomTypeEnum()), null);
    }

    /**
     * 清除当局
     */
    @Override
    public void clear() {
        this.room = null;
        if (null != this.setCard) {
            this.setCard.clean();
            this.setCard = null;
        }
        this.cleanEndSetRoom();
        this.pointList = null;
        this.setEnd = null;
        this.hMap = null;
        this.bo = null;
        this.totalPointResult = null;
    }

    @Override
    public void clearBo() {
        this.bo = null;
    }

    /**
     * 记录发起解散的玩家
     */
    public void addDissolveRoom(BaseSendMsg baseSendMsg) {
        if (this.status == DDZ_GameStatus.DDZ_GAME_STATUS_RESULT) {
            return;
        }
        DDZRoomPosMgr roomPosMgr = (DDZRoomPosMgr) this.room.getRoomPosMgr();
        this.getRoomPlayBack().addPlaybackList(baseSendMsg, roomPosMgr.getAllPlayBackNotify());
    }

    @Override
    public boolean checkExistPrizeType(PrizeType prizeType) {
        return prizeType.equals(this.room.getBaseRoomConfigure().getPrizeType());
    }

    /**
     * 更改状态
     */
    public void onChangeStatus(DDZ_GameStatus status) {
        if (status == DDZ_GameStatus.DDZ_GAME_STATUS_COMPARE) {
            setOpPos(landowner);
        }
        setStatus(status);
        getRoomPlayBack().playBack2All(SDDZ_ChangeStatus.make(this.room.getRoomID(), this.getStatus().value(), m_OpPos,
                roomDouble, holeCards, landowner, addDoubleList));
    }

    /**
     * 明牌用户
     *
     * @return
     */
    public int getFirstOps() {
        if (room.shangJuXianJiao() && room.getLastWinPos() > -1) {
            return room.getLastWinPos();
        }
        if (room.getFirstStartOpenPos() >= 0) {//有人明牌开始
            return room.getFirstStartOpenPos();
        } else {//没人明牌开始
            if (room.getFirstOpenPos() >= 0) {//有人明牌
                return room.getFirstOpenPos();
            }
        }

        return Random.nextInt(room.getPlayerNum());
    }

    public boolean update(int sec) {
        boolean isClose = false;
        switch (this.getStatus()) {
            case DDZ_GAME_STATUS_OPENCARD://明牌开始阶段
                if (CommTime.nowMS() - this.startMS >= this.getWaitTimeByStatus()) {
                    for (int i = 0; i < room.getPlayerNum(); i++) {
                        DDZRoomPos tempPos = (DDZRoomPos) this.room.getRoomPosMgr().getPosByPosID(i);
                        if (tempPos.getOpenCardStartGame() == -1) {
                            tempPos.setOpenCardStartGame(0);
                        }
                    }
                    this.startSet();
                    onChangeStatus(DDZ_GameStatus.DDZ_GAME_STATUS_SENDCARD);
                }
                break;
            case DDZ_GAME_STATUS_SENDCARD://发牌阶段
                //进入叫地主阶段
                if (!checkFaPai() || CommTime.nowMS() - this.startMS >= this.getWaitTimeByStatus()) {
                    m_OpPos = getFirstOps();
                    onChangeStatus(DDZ_GameStatus.DDZ_GAME_STATUS_CONFIRMTHELANDLORD);
                }
                break;
            //叫地主阶段
            case DDZ_GAME_STATUS_CONFIRMTHELANDLORD:
                //超时叫地主
                if (CommTime.nowMS() - this.startMS >= this.getWaitTimeByStatus()) {
                    if (room.shuangWang()) {
                        DDZRoomPos roomPos = (DDZRoomPos) this.room.getRoomPosMgr().getPosByPosID(m_OpPos);
                        boolean existZhaDan = roomPos.getPrivateCards().stream().filter(i -> BasePocker.getCardValueEx(i) == 15).count() == 4;
                        boolean existWang = roomPos.getPrivateCards().stream().filter(i -> BasePocker.getCardValueEx(i) > 15).count() == 2;
                        if (existZhaDan || existWang) {
                            //4张2
                            this.onHog(null, roomPos.getPid(), CDDZ_Hog.make(this.room.getRoomID(), nowHog + 1));
                        } else {
                            this.onHog(null, roomPos.getPid(), CDDZ_Hog.make(this.room.getRoomID(), 0));
                        }
                    } else {
                        DDZRoomPos roomPos = (DDZRoomPos) this.room.getRoomPosMgr().getPosByPosID(m_OpPos);
                        this.onHog(null, roomPos.getPid(), CDDZ_Hog.make(this.room.getRoomID(), 0));
                    }
                }
                break;
            //加倍阶段
            case DDZ_GAME_STATUS_ADDDOUBLE:
                //超时自动加倍
                onAllAddDouble();
                break;
            case DDZ_GAME_STATUS_COMPARE:
                if (this.curRound == null) {
                    if (!this.startNewRound()) {
                        this.endSet();
                    }
                } else if (this.curRound != null) {
                    boolean isRoundClosed = this.curRound.update();
                    if (isRoundClosed) {
                        if (this.curRound.isSetEnd() || !this.startNewRound()) {
                            this.endSet();
                        }
                    }
                }
                break;
            case DDZ_GAME_STATUS_RESULT:
                isClose = true;
                cleanEndSetRoom();
                break;
            default:
                break;
        }

        return isClose;
    }

    /**
     * 抢地主
     *
     * @param request
     * @param pid
     * @param hogData
     */
    public void onHog(WebSocketRequest request, long pid, CDDZ_Hog hogData) {
        //不是抢地主阶段
        if (this.status != DDZ_GameStatus.DDZ_GAME_STATUS_CONFIRMTHELANDLORD) {
            if (null != request) {
                request.error(ErrorCode.NotAllow, "onHog error:state is:" + this.status);
            }
            return;
        }
        //位置不存在
        DDZRoomPos pos = (DDZRoomPos) this.room.getRoomPosMgr().getPosByPid(pid);
        if (null == pos) {
            if (null != request) {
                request.error(ErrorCode.NotAllow, "onHog error:not find player pos  pid:" + pid);
            }
            return;
        }
        //不是你的回合
        if (m_OpPos != pos.getPosID()) {
            if (null != request) {
                request.error(ErrorCode.NotAllow, "onHog error:you can not do currpos=" + m_OpPos);
            }
            return;
        }
        if (room.shuangWang()) {
            DDZRoomPos roomPos = (DDZRoomPos) this.room.getRoomPosMgr().getPosByPosID(m_OpPos);
            boolean existZhaDan = roomPos.getPrivateCards().stream().filter(i -> BasePocker.getCardValueEx(i) == 15).count() == 4;
            boolean existWang = roomPos.getPrivateCards().stream().filter(i -> BasePocker.getCardValueEx(i) > 15).count() == 2;
            if (existZhaDan || existWang) {
                if (hogData.hog <= 0) {
                    return;
                }
            }
        }
        //进行抢地主
        if (hogData.hog > 0) {
            //更新叫地主倍数,4次抢地主确认地主
            hogCount++;
            //最后抢地主或者叫分玩家
            lastHogPos = pos.getPosID();
            //叫分倍数
            if (this.room.getRoomCfg().getQuedingdizhu() == DDZ_ConfirmTheLandlord.CONFIRM_THE_LANDLORD_ROB.value()) {
                Double doubleNum = Math.pow(2, hogCount - 1);
                hogScore = doubleNum.intValue();
            } else {
                hogScore = hogData.hog;
            }
            nowHog = hogData.hog;
        }
        //更新叫地主列表
        this.hogList.set(pos.getPosID(), hogData.hog);
        //操作位流转
        turnPos();
        //检测叫地主或者叫分结束
        int result = checkHogEnd();
        if (result == 1) {
            this.room.createSet();
        } else if (result == 2) {
            m_OpPos = landowner = (lastHogPos > -1 ? lastHogPos : 0);
            //通知地主产生进入加倍
            sendHoleCard(pos.getPosID(), hogData.hog);
        } else {
            //通知抢地主
            getRoomPlayBack().playBack2All(SDDZ_Hog.make(hogData.roomID, pos.getPosID(), hogData.hog, m_OpPos, landowner, holeCards,
                    hogScore, roomDouble, hogCount, isHaveHog()));
        }
        if (null != request) {
            request.response();
        }
    }

    /**
     * 发送底牌并通知地主
     */
    public void sendHoleCard(int opPosID, int hog) {
        //给地主底牌
        if (this.room.isGodCard() && this.room.getConfigMgr().getHoldCard().size() > 0) {
            this.holeCards.addAll(this.room.getConfigMgr().getHoldCard());
        } else {
            holeCards.addAll(this.setCard.getLeftCards().subList(0, 3));
        }
        //给地主加底牌
        DDZRoomPos landownerPos = (DDZRoomPos) this.room.getRoomPosMgr().getPosByPosID(landowner);
        landownerPos.addAllCard((List<Integer>) this.holeCards.clone());
        //底牌倍数
        addHoleCardsDouble();
        //通知抢地主
        getRoomPlayBack().playBack2All(SDDZ_Hog.make(room.getRoomID(), opPosID, hog, m_OpPos, landowner,
                holeCards, hogScore, roomDouble, hogCount, isHaveHog()));
        if (room.isDisAddDouble()) {
            //通知局状态改变，进入加倍
            onChangeStatus(DDZ_GameStatus.DDZ_GAME_STATUS_COMPARE);
        } else {
            //通知局状态改变，进入加倍
            onChangeStatus(DDZ_GameStatus.DDZ_GAME_STATUS_ADDDOUBLE);
        }
    }

    /**
     * 根据底牌添加底牌倍数 没有实现
     */
    public void addHoleCardsDouble() {
        //3张底牌才有倍数
        if (this.holeCards.size() != 3 || room.isNotCoverDouble()) {
            return;
        }
        ArrayList<Integer> kingList = new ArrayList<>(Arrays.asList(BasePocker.Trump_PockerList));
        //单张同色
        int firstHoleCard = holeCards.get(0);
        //排序
        holeCards.sort(BasePockerLogic.sorterSmallToBigHaveTrump);
        boolean allCardValueSame = holeCards.stream().allMatch(n -> BasePocker.getCardValueEx(n) == BasePocker.getCardValueEx(firstHoleCard));
        boolean allCardColorSame = holeCards.stream().allMatch(n -> BasePocker.getCardColor(n) == BasePocker.getCardColor(firstHoleCard));
        long distinctCount = holeCards.stream().map(n -> BasePocker.getCardValueEx(n.intValue())).distinct().count();
        int difference = BasePocker.getCardValueEx(holeCards.get(holeCards.size() - 1)) - BasePocker.getCardValueEx(holeCards.get(0));
        Map<Integer, List<Integer>> groupMap = holeCards.stream().collect(Collectors.groupingBy(n -> BasePocker.getCardValueEx(n)));
        boolean isStraight = distinctCount == holeCards.size() && difference == 2 && !groupMap.containsKey(twoValue);
        if (this.holeCards.containsAll(kingList)) {//同时包含大小王：*4
            roomDouble *= 4;
        } else if (allCardValueSame) {//三条
            roomDouble *= 4;
        } else if (allCardColorSame && isStraight) {//同花顺
            roomDouble *= 4;
        } else if (allCardColorSame) { //同花
            roomDouble *= 3;
        } else if (isStraight) { //顺子
            roomDouble *= 3;
        } else {
            for (Integer byte1 : kingList) {
                if (this.holeCards.contains(byte1)) {
                    roomDouble *= 2;
                }
            }
        }
    }

    /**
     * 自动所有人加倍
     */
    public void onAllAddDouble() {
        if (this.getStatus() != DDZ_GameStatus.DDZ_GAME_STATUS_ADDDOUBLE) {
            return;
        }
        if (CommTime.nowMS() - this.startMS < this.getWaitTimeByStatus()) {
            return;
        }
        for (int i = 0; i < this.room.getPlayerNum(); i++) {
            if (this.addDoubleList.get(i) == -1) {
                int addDouble = 0;
                this.addDoubleList.set(i, addDouble);
                this.room.getRoomPosMgr().notify2All(SDDZ_AddDouble.make(this.room.getRoomID(), i, addDouble));
            }
        }
        if (this.addDoubleList.stream().allMatch(n -> n.intValue() != -1)) {
            onChangeStatus(DDZ_GameStatus.DDZ_GAME_STATUS_COMPARE);
            m_OpPos = landowner;
        }
    }

    /**
     * 操作位流转
     */
    public void turnPos() {
        for (int i = 1; i <= this.room.getPlayerNum(); i++) {
            int turnPos = (m_OpPos + i) % this.room.getPlayerNum();
            if (this.hogList.get(turnPos) == 0) {
                continue;
            }
            //操作位流转
            m_OpPos = turnPos;
            break;
        }
        this.startMS = CommTime.nowMS();
    }

    /**
     * 检测是否结束抢地主
     *
     * @return 0:抢地主或者叫分还未结束1：重新发牌2：地主选取完毕
     */
    public int checkHogEnd() {
        int playerNum = this.room.getPlayerNum();
        //弃权人数
        long waiverCount = this.hogList.stream().filter(m -> m.intValue() == 0).count();
        //加码人数
        long raiseCount = this.hogList.stream().filter(m -> m.intValue() > 0).count();
        //加码3分人数
        long threeCount = this.hogList.stream().filter(m -> m.intValue() >= 3).count();
        //叫地主方式
        if (this.room.getRoomCfg().getQuedingdizhu() == DDZ_ConfirmTheLandlord.CONFIRM_THE_LANDLORD_ROB.value()) {
            //4次加倍，确认地主
            if ((waiverCount == 0 && hogCount >= 4) || (waiverCount == 1 && hogCount >= 3)) {
                return 2;
            }
        } else if (threeCount > 0) {
            //3分结束
            return 2;
        }
        //都弃权就重新发牌
        if (waiverCount == playerNum) {
            return 1;
        }
        //只有一个人叫地主或者没人第二轮没人跟你抢地主
        //只有一个人叫分或者没人第二轮没人跟你加分
        if (waiverCount == playerNum - 1 && raiseCount == 1) {
            return 2;
        }
        return 0;
    }

    /**
     * 清空结束房间当前局
     */
    public void cleanEndSetRoom() {
        // 清空回合记录
        if (null != this.historyRound) {
            this.historyRound.forEach(key -> {
                if (null != key) {
                    key.clean();
                }
            });
            this.historyRound.clear();
            this.historyRound = null;
        }
        // 清空当前回合
        if (null != this.curRound) {
            this.curRound.clean();
            this.curRound = null;
        }
        // 房间回放
        if (null != this.roomPlayBack) {
            this.roomPlayBack.clear();
            this.roomPlayBack = null;
        }
    }

    /**
     * 设置状态
     */
    public void setStatus(DDZ_GameStatus state) {
        if (this.status == state) {
            return;
        }
        this.status = state;
        this.startMS = CommTime.nowMS();
    }

    /**
     * 获取状态
     */
    public DDZ_GameStatus getStatus() {
        return this.status;
    }


    /**
     * 开启新的回合
     *
     * @return
     */
    public boolean startNewRound() {
        if (this.curRound != null) {
            this.historyRound.add(this.curRound);
        }

        this.curRound = new DDZRoomSetRound(this); // 开启第一轮
        return true;
    }

    /**
     * 发牌开始
     */
    public void startSet() {
        // 初始化位置
        this.initSetPos();
        //给地主底牌
        if (this.room.isGodCard() && this.room.getConfigMgr().getHoldCard().size() > 0) {
            BasePockerLogic.deleteCard(this.setCard.getLeftCards(), (ArrayList<Integer>) this.room.getConfigMgr().getHoldCard());
        }
        //是否开启神牌模式
        if (room.isGodCard())
            godCard();
        for (int i = 0; i < this.room.getXiPaiList().size(); i++) {
            this.setCard.onXiPai();
        }
        this.room.getXiPaiList().clear();
        for (int j = 0; j < this.room.getPlayerNum(); j++) {
            DDZRoomPos roomPos = (DDZRoomPos) this.room.getRoomPosMgr().getPosByPosID((m_OpPos + j) % this.room.getPlayerNum());
            //如果是DEBUG模式发送神牌
            if (room.isGodCard()) {
                //获取神牌牌堆
                roomPos.init(hMap.get(j));
            } else {
                roomPos.init(this.setCard.popList(setCard.getCardSize()));
            }
        }
        //更新地主
        setDefeault();
        //设置出牌玩家,如果有地主了地主出牌，
        this.m_OpPos = getFirstOps();
        this.startMS = CommTime.nowMS();
        DDZRoomPosMgr roomPosMgr = (DDZRoomPosMgr) this.room.getRoomPosMgr();
        //开始发牌
        for (int i = 0; i < this.room.getPlayerNum(); i++) {
            long pid = this.room.getRoomPosMgr().getPosByPosID(i).getPid();
            if (0 == i) {
                //只记录一次setStart到数据库，并发送setStart
                this.getRoomPlayBack().playBack2Pos(i, SDDZ_SetStart.make(this.room.getRoomID(), this.getNotify_set(pid)), roomPosMgr.getAllPlayBackNotify());
            } else {
                this.room.getRoomPosMgr().notify2Pos(i, SDDZ_SetStart.make(this.room.getRoomID(), this.getNotify_set(pid)));
            }
        }
        this.room.getTrusteeship().setTrusteeshipState(TrusteeshipState.Normal);
    }

    /**
     * 默认位置
     **/
    public void setDefeault() {
        int playerNum = this.room.getPlayerNum();
        for (int i = 0; i < playerNum; i++) {
            DDZRoomPos tempPos = (DDZRoomPos) this.room.getRoomPosMgr().getPosByPosID(i);
            if (tempPos.getOpenCardStartGame() == 1) {
                // 明牌开始五倍
                this.openMultipleCard.set(tempPos.getPosID(), 5);
                this.openCardList.set(tempPos.getPosID(), 1);
            }
        }
    }

    public void calcPosPoint(DDZSetPos mSetPos) {
        int point = mSetPos.getEndPoint() + mSetPos.getDeductPoint();
        mSetPos.setEndPoint(point);
        mSetPos.setDeductEndPoint(CommMath.addDouble(mSetPos.getDeductEndPoint(), mSetPos.getDeductPointYiKao()));
    }

    /**
     * 亲友圈竞技点不能输到0分
     */
    @SuppressWarnings("Duplicates")
    public void calYiKaoPoint() {
        // 各个位置的算分情况map
        double beiShu = Math.max(0D, this.room.getRoomTyepImpl().getSportsDouble());
        //各个位置的输分情况
        Map<Integer, Double> pointMap = new HashMap<>();
        //各个位置的最多能输多少分
        Map<Integer, Double> sportPointMap = new HashMap<>();
        if (!(room.isOnlyWinRightNowPoint() && RoomTypeEnum.UNION.equals(room.getRoomTypeEnum()))) {
            //身上多少分赢多少分
            // 初始化一科计算分数所需要的map
            this.getPosDict().values().forEach(k -> {
                k.setDeductPoint(pointList.get(k.getPosID()));
                k.setDeductPointYiKao(CommMath.mul(k.getDeductPoint(), beiShu));
            });
        }
        // 初始化一科计算分数所需要的map
        this.getPosDict().values().forEach(k -> {
            pointMap.put(k.getPosID(), CommMath.mul(k.getDeductPoint(), beiShu));
            sportPointMap.put(k.getPosID(), k.getRoomPos().getRoomSportsPoint());
        });
        DDZSetPos sPos = this.getPosDict().values().stream().max(Comparator.comparingInt(m -> m.getDeductPoint())).get();
        int huPos = sPos.getPosID();
        // 亲友圈竞技点不能输到0分
        if (room.isRulesOfCanNotBelowZero() && RoomTypeEnum.UNION.equals(this.room.getRoomTypeEnum()) && huPos >= 0) {
            Double totalWinPoint = 0D;//输的总分
            for (int i = 0; i < room.getPlayerNum(); i++) {
                DDZSetPos setPos = this.getPosDict().get(i);
                Double losePoint = setPos.getDeductPointYiKao();//-12
                if (losePoint <= 0) {
                    //如果这个玩家本身没有分数可以扣 设置为0  继续下一个玩家计算
                    if (sportPointMap.get(setPos.getPosID()) <= 0) {
                        setPos.setDeductPointYiKao(0);
                        continue;
                    }
                    // 一科分数限制 10
                    if (sportPointMap.get(setPos.getPosID()) - Math.abs(losePoint) < 0) {
                        //输的分数为-的
                        losePoint = CommMath.mul(sportPointMap.get(setPos.getPosID()), -1);
                        setPos.setDeductPointYiKao(losePoint);
                    }
                    totalWinPoint = CommMath.addDouble(totalWinPoint, Math.abs(losePoint));
                }
            }
            for (int i = 0; i < room.getPlayerNum(); i++) {
                DDZSetPos setPos = this.getPosDict().get(i);
                Double winPoint = setPos.getDeductPointYiKao();//12
                if (totalWinPoint <= 0) {
                    for (int j = i; j < room.getPlayerNum(); j++) {
                        DDZSetPos setPos2 = this.getPosDict().get(j);
                        if (setPos2.getDeductPointYiKao() >= 0) {
                            setPos2.setDeductPointYiKao(0);
                        }
                    }
                    break;
                }
                if (winPoint > 0) {
                    if (totalWinPoint < winPoint) {
                        setPos.setDeductPointYiKao(totalWinPoint);
                        totalWinPoint = CommMath.subDouble(totalWinPoint, totalWinPoint);
                    } else {
                        totalWinPoint = CommMath.subDouble(totalWinPoint, winPoint);
                    }
                }
            }

        }
    }


    /**
     * 局结束
     */
    public void endSet() {
        //printCallStatck();
        //已经结算过当局，返回
        if (this.status == DDZ_GameStatus.DDZ_GAME_STATUS_RESULT)
            return;

        this.setStatus(DDZ_GameStatus.DDZ_GAME_STATUS_RESULT);
        this.calPoint();
        this.checkEndConditions();
        setTrusteeshipAutoDissolution();

        ArrayList<Integer> beiShuList = this.getDoubleNumList();
        roomPlayBack();
        if (this.room.getDissolveRoom() == null) {
            // 广播
            getRoomPlayBack().playBack2All(SDDZ_SetEnd.make(this.room.getRoomID(), this.status.value(), this.startMS, roomDouble,
                    this.room.getBaseMark(), pointList, beiShuList, this.robCloseList, landowner, this.bo.getPlayBackCode(), this.sportsPointList));
        }

        for (int i = 0; i < this.room.getPlayerNum(); i++) {
            DDZRoomPos pos = (DDZRoomPos) this.room.getRoomPosMgr().getPosByPosID(i);
            if (null != pos) {
                pos.setOpenCardStartGame(-1);
            }
        }
        room.setFirstStartOpenPos(0, true);
    }

    /**
     * 判断结束条件
     */
    private void checkEndConditions() {
        //同时勾选了这两个玩法 比赛分有小等于0的  房间直接结束
        if (room.isOnlyWinRightNowPoint() && room.isRulesOfCanNotBelowZero()) {
            if (RoomTypeEnum.UNION.equals(room.getRoomTypeEnum())) {
                for (int i = 0; i < room.getPlayerNum(); i++) {
                    AbsRoomPos roomPos = room.getRoomPosMgr().getPosByPosID(i);
                    if (roomPos.getRoomSportsPoint() <= 0) {
                        room.isEnd = true;
                    }
                }
            }
        }
    }

    /**
     * 获取各个玩家的陪数列表
     */
    public ArrayList<Integer> getDoubleNumList() {
        ArrayList<Integer> beiShuList = new ArrayList<Integer>(Collections.nCopies(this.room.getPlayerNum(), 0));
        if (landowner == -1) {
            return beiShuList;
        }
        for (int i = 0; i < this.room.getPlayerNum(); i++) {
            if (i == landowner) {
                continue;
            }
            //底牌倍数*抢地主的倍数*农民的倍数*地主的倍数
            int landOwerDouble = this.roomDouble * this.getDoubleByPos(i) * this.getDoubleByPos(landowner)
                    * getHogScore();
            beiShuList.set(i, landOwerDouble);
            beiShuList.set(landowner, beiShuList.get(landowner) + landOwerDouble);
        }
        return beiShuList;
    }

    /**
     * 获取个人陪数
     */
    public int getDoubleByPos(int pos) {
        //加倍倍数*明牌倍数*春天或者反春天的倍数
        return this.getAddDouble(pos) * this.getOpenMultiple(pos) * this.getRobCloseDouble(pos);
    }

    /**
     * 获取加倍
     */
    public int getOpenMultiple(int pos) {
        if (pos < 0) {
            return 1;
        }
        int openMultiple = this.openMultipleCard.get(pos);
        return openMultiple == 0 ? 1 : openMultiple;
    }

    /**
     * 获取春天反春天的倍数
     */
    public int getRobCloseDouble(int pos) {
        if (pos < 0) {
            return 1;
        }
        int robClose = robCloseList.get(pos);
        return robClose == 0 ? 1 : 2;
    }

    /**
     * 获取加倍
     */
    public int getAddDouble(int pos) {
        int addDouble = this.addDoubleList.get(pos);
        if (addDouble == -1) {
            return 1;
        }
        return addDouble == 1 ? 2 : 1;
    }

//    public static void printCallStatck() {
//        Throwable ex = new Throwable();
//        StackTraceElement[] stackElements = ex.getStackTrace();
//        if (stackElements != null) {
//            for (int i = 0; i < stackElements.length; i++) {
//                System.out.print(stackElements[i].getClassName() + "/t");
//                System.out.print(stackElements[i].getFileName() + "/t");
//                System.out.print(stackElements[i].getLineNumber() + "/t");
//                System.out.println(stackElements[i].getMethodName());
//                System.out.println("-----------------------------------");
//            }
//        }
//    }

    //设置所有玩家都准备进行下一场游戏
    public void setAllGameReady(boolean flag) {
        if (this.room.getCurSetID() >= this.room.cfg.getSetCount()) return;
        for (AbsRoomPos pos : this.room.getRoomPosMgr().getPosList()) {
            if (pos.getPid() != 0) {
                pos.setGameReady(flag);
                if (flag) pos.setLatelyOutCardTime(0L);
            }
        }
    }

    /**
     * 结算积分
     */
    public void calPoint() {
        GameSetBO gameSetBO = ContainerMgr.get().getComponent(GameSetBOService.class).findOne(room.getRoomID(), this.room.getCurSetID());
        this.bo = gameSetBO == null ? new GameSetBO() : gameSetBO;
        if (gameSetBO == null) {
            bo.setRoomID(room.getRoomID());
            bo.setSetID(this.room.getCurSetID());
            bo.setTabId(this.room.getTabId());
        }
        //结算分数
        DDZGameResult result = new DDZGameResult(this.room);
        int winPos = result.calPoint();
        //更新最早出完牌的玩家
        room.setLastWinPos(winPos);
        for (int i = 0; i < this.room.getPlayerNum(); i++) {
            if (PrizeType.Gold == this.room.getBaseRoomConfigure().getPrizeType()) {
                this.pointList.set(i, this.pointList.get(i) * this.room.getBaseMark());
            }
        }
        for (int i = 0; i < this.room.getPlayerNum(); i++) {
            DDZRoomPos roomPos = (DDZRoomPos) this.room.getRoomPosMgr().getPosByPosID(i);
            if (winPos != -1) {
                if (i == winPos) {
                    roomPos.addWin(1);
                } else {
                    roomPos.addLose(1);
                }
            } else {
                roomPos.addFlat(1);
            }
        }
        this.onlyWinRightNowPoint();
        this.calYiKaoPoint();
        this.getPosDict().values().forEach(k -> calcPosPoint(k));
        //分数扣除金币，并通知客户端
        for (int i = 0; i < this.room.getPlayerNum(); i++) {
            DDZRoomPos roomPos = (DDZRoomPos) this.room.getRoomPosMgr().getPosByPosID(i);
            DDZSetPos setPos = this.posDict.get(i);
            DDZRoom_PosEnd posEnd = roomPos.calcPosEnd(setPos);
            goldEnd(i, this.pointList.get(i));
            if (CollectionUtils.isNotEmpty(this.sportsPointList)) {
                this.sportsPointList.set(posEnd.pos, Objects.isNull(posEnd.sportsPoint) ? 0D : posEnd.sportsPoint);
            }
            this.setEnd.posResultList.add(posEnd);
            totalPointResult.add(roomPos.getPoint());
        }

        room.getRoomPosMgr().setAllLatelyOutCardTime();
        this.setEnd.endTime = CommTime.nowSecond();
        DDZRoom_SetEnd lSetEnd = this.getNotify_setEnd();

        String gsonSetEnd = new Gson().toJson(lSetEnd);
        bo.setPlayBackCode(getPlayBackDateTimeInfo().getPlayBackCode());
        bo.setDataJsonRes(gsonSetEnd);
        bo.setEndTime(setEnd.endTime);
        bo.getBaseService().saveOrUpDate(bo);
    }

    /**
     * 练习场结算
     */
    private void goldEnd(int posID, int shui) {
        if (this.checkExistPrizeType(PrizeType.Gold)) {
            DDZRoomPos pos = (DDZRoomPos) this.room.getRoomPosMgr().getPosByPosID(posID);
            if (!RobotMgr.getInstance().isRobot((int) pos.getPid())) {
                Player player = PlayerMgr.getInstance().getPlayer(pos.getPid());
                player.getFeature(PlayerCurrency.class).goldRoomEnd(shui, room.getBaseMark(),
                        this.room.getBaseRoomConfigure().getGameType().getId());
            } else {
                RobotMgr.getInstance().freeRobot((int) pos.getPid());
            }
        }
    }

    /**
     * 获取分数
     */
    public int getHogScore() {
        return hogScore <= 0 ? 1 : hogScore;
    }

    /**
     * 获取通知设置
     *
     * @param pid 用户ID
     * @return
     */
    public DDZRoomSetInfo getNotify_set(long pid) {
        DDZRoomSetInfo ret = new DDZRoomSetInfo();
        ret.roomID = this.room.getRoomID();
        ret.setSetID(this.room.getCurSetID());
        ret.startTime = this.startMS;
        ret.state = this.status.value();
        ret.opPos = m_OpPos;
        ret.landowner = landowner;
        ret.isFirstOp = bFirstOp;
        ret.roomDouble = roomDouble;
        ret.holeCards = holeCards;
        ret.cardNumMap = this.setCard.getCardNumMap();
        ret.baseMark = this.room.getBaseMark();
        ret.hogScore = hogScore;
        ret.hogCount = hogCount;
        ret.isHaveHog = isHaveHog();
        if (null != this.curRound) {
            ret.lastOpPos = this.curRound.getLastOpPos();
            ret.opType = this.curRound.getOpCardType();
            ret.cardList = this.curRound.getCardList();
            if (null != ret.cardList) {
                ret.cardList.sort(BasePockerLogic.sorterBigToSmallHaveTrump);
            }
            ret.opPos = this.curRound.getOpPos();
            ret.isSetEnd = this.curRound.isSetEnd();
        }
        ArrayList<Integer> beiShuList = this.getDoubleNumList();
        if (this.status == DDZ_GameStatus.DDZ_GAME_STATUS_RESULT) {
            SDDZ_SetEnd end = SDDZ_SetEnd.make(this.room.getRoomID(), this.status.value(), this.startMS, roomDouble,
                    this.room.getBaseMark(), pointList, beiShuList, this.robCloseList, landowner, this.bo.getPlayBackCode(), this.sportsPointList);
            ret.setEnd = end;
        }
        if (this.status == DDZ_GameStatus.DDZ_GAME_STATUS_RESULT) {
            ret.playBackCode = getPlayBackDateTimeInfo().getPlayBackCode();
        }
        // 每个玩家的牌面
        ret.posInfo = new ArrayList<>();
        for (int i = 0; i < this.room.getPlayerNum(); i++) {
            DDZRoomPos roomPos = (DDZRoomPos) this.room.getRoomPosMgr().getPosByPosID(i);
            RoomPosInfo room_Pos = this.room.getRoomPosMgr().getNotify_PosList().get(i);
            int setPoint = this.pointList.get(i);
            DDZRoomSet_Pos roomSet_Pos = new DDZRoomSet_Pos();
            roomSet_Pos.posID = room_Pos.getPos();
            roomSet_Pos.pid = room_Pos.getPid();
            roomSet_Pos.cards = roomPos.getNotifyCard(pid, this.openCardList.get(room_Pos.getPos()) == 1);
            roomSet_Pos.addDouble = this.addDoubleList.get(room_Pos.getPos());
            roomSet_Pos.openCard = this.openCardList.get(room_Pos.getPos());
            roomSet_Pos.robClose = this.robCloseList.get(room_Pos.getPos());
            roomSet_Pos.point = setPoint;
            roomSet_Pos.isLandowner = this.landowner == room_Pos.getPos();
            roomSet_Pos.hog = this.hogList.get(room_Pos.getPos());
            roomSet_Pos.doubleNum = beiShuList.get(room_Pos.getPos());
            roomSet_Pos.sportsPoint = roomPos.setSportsPoint(setPoint);
            ret.posInfo.add(roomSet_Pos);
        }

        return ret;
    }

    /**
     * 获取通知设置结束
     *
     * @return
     */
    public DDZRoom_SetEnd getNotify_setEnd() {
        return setEnd;
    }

    //托管
    public void roomTrusteeship(int pos) {
        if (null != this.curRound) this.curRound.roomTrusteeship(pos);
    }

    /**
     * 获取阶段时间
     *
     * @return
     */
    public int getWaitTimeByStatus() {
        int waitTime = 0;
        switch (this.status) {
            case DDZ_GAME_STATUS_OPENCARD:
                waitTime = 5000;
                break;
            case DDZ_GAME_STATUS_SENDCARD:
                waitTime = 15000;
                break;
            case DDZ_GAME_STATUS_CONFIRMTHELANDLORD:
                waitTime = 15000;
                break;
            case DDZ_GAME_STATUS_COMPARE:
                waitTime = 30000;
                break;
            case DDZ_GAME_STATUS_RESULT:
                waitTime = 15000;
                break;
            case DDZ_GAME_STATUS_ADDDOUBLE:
                waitTime = 5000;
                break;
            default:
                break;
        }
        return waitTime;
    }

    /**
     * @return curRound
     */
    public DDZRoomSetRound getCurRound() {
        return curRound;
    }


    /**
     * 获取房间回放记录
     *
     * @return
     */
    public RoomPlayBack getRoomPlayBack() {
        if (null == this.roomPlayBack)
            this.roomPlayBack = new DDZRoomPlayBackImpl(this.room);
        return this.roomPlayBack;
    }

    /**
     * 如果是房卡类型，才需要回放记录
     */
    public void roomPlayBack() {
        if (this.checkExistPrizeType(PrizeType.RoomCard)) {
            PlayBackData playBackData = new PlayBackData(this.room.getRoomID(),
                    this.room.getCurSetID(), 0, this.room.getCount(),
                    this.room.getRoomKey(),
                    this.room.getBaseRoomConfigure().getGameType().getId(), getPlayBackDateTimeInfo());
            this.getRoomPlayBack().addPlayBack(playBackData);
        }
    }

    /**
     * 插入牌 并在牌堆里面删除
     */
    public ArrayList<Integer> getGodCard(ArrayList<Integer> list) {
        if (!room.isGodCard()) return new ArrayList<Integer>();
        int cardNum = setCard.getCardSize();
        ArrayList<Integer> cardList = new ArrayList<Integer>(cardNum);
        cardList.addAll(list);
        int count = cardNum - cardList.size();
        ArrayList<Integer> tempList = this.setCard.popList(count);
        BasePockerLogic.deleteCard(this.setCard.getLeftCards(), tempList);
        cardList.addAll(tempList);
        return cardList;
    }

    /**
     * 设置神牌
     */
//	0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,  0x0E,	0x0F, //方块3~2
//	0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D,  0x1E,	0x1F, //梅花3~2
//	0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D,  0x2E,	0x2F, //红桃3~2
//	0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D,  0x3E,	0x3F, //黑桃3~2
    public void godCard() {
        if (!room.isGodCard()) return;
        boolean flag1 = BasePockerLogic.deleteCard(this.setCard.getLeftCards(), room.getConfigMgr().getPrivate_Card1());
        boolean flag2 = BasePockerLogic.deleteCard(this.setCard.getLeftCards(), room.getConfigMgr().getPrivate_Card2());
        boolean flag3 = BasePockerLogic.deleteCard(this.setCard.getLeftCards(), room.getConfigMgr().getPrivate_Card3());
        if (flag1 && flag2 && flag3) {
            ArrayList<Integer> card1 = getGodCard(room.getConfigMgr().getPrivate_Card1());
            ArrayList<Integer> card2 = getGodCard(room.getConfigMgr().getPrivate_Card2());
            ArrayList<Integer> card3 = getGodCard(room.getConfigMgr().getPrivate_Card3());
            hMap.put(0, card1);
            hMap.put(1, card2);
            hMap.put(2, card3);
        } else {
            this.setCard.randomCard();
            int cardNum = setCard.getCardSize();
            hMap.put(0, this.setCard.popList(cardNum));
            hMap.put(1, this.setCard.popList(cardNum));
            hMap.put(2, this.setCard.popList(cardNum));
        }
    }

    /**
     * @return m_OpPos
     */
    public int getOpPos() {
        return m_OpPos;
    }

    /**
     * @param m_OpPos 要设置的 m_OpPos
     */
    public void setOpPos(int m_OpPos) {
        DDZRoomPos tempRoomPos = (DDZRoomPos) this.room.getRoomPosMgr().getPosByPosID(m_OpPos);
        tempRoomPos.setLatelyOutCardTime(CommTime.nowMS());
        this.m_OpPos = m_OpPos;
    }

    public void onOpenCard(WebSocketRequest request, long pid, CDDZ_OpenCard openCard) {
        if (!room.isCanOpenCard()) {
            request.error(ErrorCode.NotAllow, "!room.isCanOpenCard():" + !room.isCanOpenCard());
            return;
        }
        DDZRoomPos pos = (DDZRoomPos) this.room.getRoomPosMgr().getPosByPid(pid);
        if (null == pos) {
            if (null != request) {
                request.error(ErrorCode.NotAllow, "onOpenCard error:not find player pos  pid:" + pid);
            }
            return;
        }
        //已经明牌
        if (-1 != this.openCardList.get(pos.getPosID())) {
            if (null != request) {
                request.error(ErrorCode.NotAllow, "onOpenCard error:you already opened");
            }
            return;
        }
        //不是发牌阶段，无法进行明牌
        if (this.getStatus() != DDZ_GameStatus.DDZ_GAME_STATUS_SENDCARD) {
            if (null != request) {
                request.error(ErrorCode.NotAllow, "onOpenCard error:state is error" + getStatus());
            }
            return;
        }
        this.openCardList.set(pos.getPosID(), openCard.OpenCard);
        //更新首个明牌用户
        room.setFirstOpenPos(pos.getPosID(), false);
        this.openMultipleCard.set(pos.getPosID(), openCard.multiple);
        this.room.getRoomPosMgr().notify2All(
                SDDZ_OpenCard.make(openCard.roomID, pos.getPosID(), openCard.OpenCard, pos.privateCards, roomDouble));
        if (null != request) {
            request.response();
        }
    }

    public void onAddDouble(WebSocketRequest request, long pid, CDDZ_AddDouble addDouble) {
        if (this.status != DDZ_GameStatus.DDZ_GAME_STATUS_ADDDOUBLE) {
            if (null != request) {
                request.error(ErrorCode.NotAllow,
                        "onAddDouble error:state is not  DDZ_GameStatus.DDZ_GAME_STATUS_SENDCARD  state:"
                                + this.status);
            }
            return;
        }

        DDZRoomPos pos = (DDZRoomPos) this.room.getRoomPosMgr().getPosByPid(pid);
        if (null == pos) {
            if (null != request) {
                request.error(ErrorCode.NotAllow, "onAddDouble error:not find player pos  pid:" + pid);
            }
            return;
        }

        if (-1 != this.addDoubleList.get(pos.getPosID())) {
            if (null != request) {
                request.error(ErrorCode.NotAllow, "onAddDouble error:you already add double");
            }
            return;
        }
        if (null != request) {
            request.response();
        }
        this.addDoubleList.set(pos.getPosID(), addDouble.addDouble);
        this.room.getRoomPosMgr().notify2All(SDDZ_AddDouble.make(addDouble.roomID, pos.getPosID(), addDouble.addDouble));
        if (this.addDoubleList.stream().allMatch(n -> n.intValue() != -1)) {
            onChangeStatus(DDZ_GameStatus.DDZ_GAME_STATUS_COMPARE);
            m_OpPos = landowner;
        }
    }

    public void setbFirstOp(boolean bFirstOp) {
        this.bFirstOp = bFirstOp;
    }

    /**
     * 接收客户端消息 判断是否进入游戏
     *
     * @param request
     * @param pos
     */
    public void faPaiJieShu(WebSocketRequest request, int pos) {
        if (this.getStatus() != DDZ_define.DDZ_GameStatus.DDZ_GAME_STATUS_SENDCARD) {
            if (null != request) {
                request.error(ErrorCode.NotAllow, "faPaiJieShu error:state is not  can   state:" + this.getStatus());
            }
            return;
        }
        DDZRoomPos roomPos = (DDZRoomPos) room.getRoomPosMgr().getPosByPosID(pos);
        if (roomPos == null) {
            if (null != request) {
                request.error(ErrorCode.NotAllow, "roomPos is null posID:" + pos);
            }
            return;
        }
        roomPos.setBeginFlag(true);
    }


    /**
     * 判断是否可以发牌 检查没有发送发牌消息的人有几个  有一个存在都不能发牌
     *
     * @return
     */
    private boolean checkFaPai() {
        return room.getRoomPosMgr().getPosList().stream().filter(k -> !((DDZRoomPos) k).getBeginFlag()).count() > 0;
    }

    /**
     * 是否有抢过底注
     */
    public boolean isHaveHog() {
        return hogCount > 0;
    }

    /**
     * 小局托管自动解散
     */
    public void setTrusteeshipAutoDissolution() {
        // 检查小局托管自动解散
        if (room.isSetAutoJieSan()) {
            // 获取托管玩家pid列表
            List<Long> trusteeshipPlayerList = room.getRoomPosMgr().getRoomPosList().stream().filter(n -> n.isTrusteeship()).map(n -> n.getPid()).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(trusteeshipPlayerList)) {
                // 记录回放中
                getRoomPlayBack().addPlaybackList(SDDZ_DissolveTrusteeship.make(room.getRoomID(), trusteeshipPlayerList, CommTime.nowSecond()), null);
                room.setTrusteeshipDissolve(true);
            }
        } else if (room.isSetAutoJieSan2()) {
            // 有玩家连续2局托管
            // 获取托管玩家pid列表
            List<Long> trusteeshipPlayerList = room.getRoomPosMgr().getRoomPosList().stream()
                    .filter(n -> n.isTrusteeship() && ((DDZRoomPos) n).getTuoGuanSetCount() >= 2).map(n -> n.getPid()).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(trusteeshipPlayerList)) {
                // 记录回放中
                getRoomPlayBack().addPlaybackList(SDDZ_DissolveTrusteeship.make(room.getRoomID(), trusteeshipPlayerList, CommTime.nowSecond()), null);
                room.setTrusteeshipDissolve(true);
            }
        }
    }

    /**
     * 发牌的时候记录分数
     * 只赢当前身上分的时候要用
     */
    @Override
    public void recordRoomPosPointBeginStart() {
        if (this.room.isOnlyWinRightNowPoint() && RoomTypeEnum.UNION.equals(room.getRoomTypeEnum())) {
            for (int i = 0; i < room.getPlayerNum(); i++) {
                AbsRoomPos roomPos = this.room.getRoomPosMgr().getPosByPosID(i);
                roomPos.setGameBeginSportsPoint(roomPos.getRoomSportsPoint());
            }
        }
    }

    /**
     * 亲友圈竞技点不能输到0分
     */
    @SuppressWarnings("Duplicates")
    public void onlyWinRightNowPoint() {
        // 各个位置的算分情况map
        double beiShu = Math.max(0D, room.getRoomTyepImpl().getSportsDouble());
        //各个位置的输分情况
        Map<Integer, Double> pointMap = new HashMap<>();
        //临时存储玩家最多输赢分
        Map<Integer, Double> deductPointTemp = new HashMap<>();
        //最后玩家应该输赢的竞技点
        Map<Integer, Double> resultPointTemp = new HashMap<>();
        //各个位置的最多能赢多少分
        Map<Integer, Double> sportPointMap = new HashMap<>();
        DDZSetPos sPos = this.getPosDict().values().stream().max(Comparator.comparingInt(m -> m.getDeductPoint())).get();
        int huPos = sPos.getPosID();
        if (room.isOnlyWinRightNowPoint() && RoomTypeEnum.UNION.equals(room.getRoomTypeEnum())) {
            //身上多少分赢多少分
            // 初始化一科计算分数所需要的map
            this.getPosDict().values().forEach(k -> {
                k.setDeductPoint(pointList.get(k.getPosID()));
                k.setDeductPointYiKao(CommMath.mul(k.getDeductPoint(), beiShu));
            });
        }
        //不同的情况 初始化的数据来源不同
        if (room.isRulesOfCanNotBelowZero() && RoomTypeEnum.UNION.equals(room.getRoomTypeEnum()) && huPos >= 0) {
            // 初始化一科计算分数所需要的map
            this.getPosDict().values().forEach(k -> {
                pointMap.put(k.getPosID(), k.getDeductPointYiKao());
                sportPointMap.put(k.getPosID(), k.getRoomPos().getGameBeginSportsPoint());
                //更新临时存储值
                deductPointTemp.put(k.getPosID(), k.getDeductPointYiKao());
                if (k.getDeductPointYiKao() > 0) {
                    resultPointTemp.put(k.getPosID(), k.getDeductPointYiKao());
                } else {
                    resultPointTemp.put(k.getPosID(), 0D);
                }
            });
        } else if (room.isOnlyWinRightNowPoint() && RoomTypeEnum.UNION.equals(room.getRoomTypeEnum()) && huPos >= 0) {
            // 初始化一科计算分数所需要的map
            this.getPosDict().values().forEach(k -> {
                pointMap.put(k.getPosID(), CommMath.mul(k.getDeductPoint(), beiShu));
                sportPointMap.put(k.getPosID(), k.getRoomPos().getGameBeginSportsPoint());
                //更新临时存储值
                deductPointTemp.put(k.getPosID(), k.getDeductPointYiKao());
                if (k.getDeductPointYiKao() > 0) {
                    resultPointTemp.put(k.getPosID(), k.getDeductPointYiKao());
                } else {
                    resultPointTemp.put(k.getPosID(), 0D);
                }
            });
        }

        //如果全部都在正常范围，按正常算分
        boolean allMatch = this.getPosDict().entrySet().stream().allMatch(i -> {
            DDZSetPos setPos = i.getValue();
            Double losePoint = setPos.getDeductPointYiKao();
            return setPos.getRoomPos().getGameBeginSportsPoint() < 0 || CommMath.subDouble(losePoint, setPos.getRoomPos().getGameBeginSportsPoint()) <= 0D;
        });
        if (allMatch) {
            return;
        }

        boolean isFirst = false;
        // 只能赢自己身上的分数
        if (room.isOnlyWinRightNowPoint() && RoomTypeEnum.UNION.equals(room.getRoomTypeEnum()) && huPos >= 0) {
            for (int i = 0; i < room.getPlayerNum(); i++) {
                DDZSetPos setPos = this.getPosDict().get(i);
                Double losePoint = setPos.getDeductPointYiKao();
                //没有赢分的话 不进行考虑
                if (losePoint <= 0) {
                    continue;
                }
                //需要扣减的分数
                Double needSubPoint = CommMath.subDouble(losePoint, setPos.getRoomPos().getGameBeginSportsPoint());
                //有需要扣减的话进行扣减
                if (needSubPoint > 0D) {
                    Map<Integer, Double> resultMap = this.subPointByOnlyWinRightNowPoint(deductPointTemp, setPos, isFirst, !isFirst ? this.getExceptOneOtherPoint() : 0);
                    for (int j = 0; j < this.getPosDict().size(); j++) {
                        if (resultMap.get(j) < 0) {
                            //分数进行增减
                            deductPointTemp.put(j, CommMath.addDouble(deductPointTemp.get(j), Math.abs(resultMap.get(j))));
                            resultPointTemp.put(j, CommMath.addDouble(resultPointTemp.get(j), resultMap.get(j)));
                        } else {
                            if (j == setPos.getPosID()) {
                                resultPointTemp.put(j, resultMap.get(j));
                            }
                        }
                    }
                    isFirst = true;
                }
            }
            for (int j = 0; j < this.getPosDict().size(); j++) {
                this.getPosDict().get(j).setDeductPointYiKao(resultPointTemp.get(j));
            }
        }
    }

    /**
     * 获取除了某个玩家外 其他玩家 分数超过带多少赢的
     *
     * @return
     */
    private Double getExceptOneOtherPoint() {
        Double totalValue = new Double(0D);
        for (int i = 0; i < room.getPlayerNum(); i++) {
            DDZSetPos absMJSetPos = this.getPosDict().get(i);
            if (absMJSetPos.getDeductPointYiKao() <= 0 ||
                    absMJSetPos.getDeductPointYiKao() > absMJSetPos.getRoomPos().getGameBeginSportsPoint()) {
                continue;
            }
            totalValue = CommMath.addDouble(totalValue, absMJSetPos.getDeductPointYiKao());
        }
        return totalValue;
    }

    /**
     * @param setPos  多赢的那个人
     * @param isFirst
     */
    private Map<Integer, Double> subPointByOnlyWinRightNowPoint(Map<Integer, Double> temp, DDZSetPos setPos, boolean isFirst, Double otherPoint) {
        Map<Integer, Double> resultMap = new HashMap<>(temp);
//        Map<Integer, Double> resultMap = new HashMap<>();
//        for (int i = 0; i < room.getPlayerNum(); i++) {
//            DDZSetPos absMJSetPos = this.getPosDict().get(i);
//            resultMap.put(absMJSetPos.getPosID(), absMJSetPos.getDeductPointYiKao());
//        }
        //传递参数使用
        Map<Integer, Double> resultMap2 = new HashMap<>(resultMap);

        Long newPlayerNum = resultMap.entrySet().stream().filter(k -> k.getValue() < 0).count();
        Double beginGamePoint = CommMath.addDouble(setPos.getRoomPos().getGameBeginSportsPoint(), otherPoint);
        Double newMin = CommMath.div(-beginGamePoint, newPlayerNum.intValue());
        Double minValue = resultMap.entrySet().stream().filter(k -> k.getValue() < 0).
                sorted(Comparator.comparing(k -> -k.getValue())).map(k -> k.getValue()).findFirst().orElse(0D);
        Map<Integer, Double> calcMap = this.diGuiMethod(beginGamePoint, resultMap2, minValue, newMin);

        Double addDouble = 0D;
        for (Map.Entry<Integer, Double> con : calcMap.entrySet()) {
            if (con.getValue() > 0) {
                if (con.getKey() == setPos.getPosID()) {
                    resultMap.put(con.getKey(), CommMath.subDouble(beginGamePoint, otherPoint));
                }
            }
            if (con.getValue() == 0) {
                addDouble = CommMath.addDouble(addDouble, Math.abs(resultMap.get(con.getKey())));
            }
        }
        long count = calcMap.entrySet().stream().filter(k -> k.getValue() < 0).count();
        //计算除后余不进的值，加输分最高的第一个人（例：剩10，平均3份。每人3.33，还差0.1补给第一分最低的人）
        //剩余的份数10
        double levelNum = CommMath.subDouble(beginGamePoint, addDouble);
        //平均每人3.33
        double everyCount = CommMath.div(levelNum, count);
        //还差0.01
        double difference = CommMath.subDouble(levelNum, CommMath.mul(everyCount, count));
        for (Map.Entry<Integer, Double> con : calcMap.entrySet()) {
            if (con.getValue() < 0) {
                double point = -everyCount;
                if (difference != 0) {
                    point = CommMath.addDouble(point, -difference);
                    difference = 0;
                }
                resultMap.put(con.getKey(), point);
            }
        }
        return resultMap;
//        for (int i = 0; i < room.getPlayerNum(); i++) {
//            DDZSetPos absMJSetPos = this.getPosDict().get(i);
//            if(resultMap.get(i)<0){
//                if(!isFirst){
//                    absMJSetPos.setDeductPointYiKao(resultMap.get(i));
//                }else{
//                    absMJSetPos.setDeductPointYiKao(CommMath.addDouble(absMJSetPos.getDeductPointYiKao(),resultMap.get(i)));
//                }
//            }else{
//                absMJSetPos.setDeductPointYiKao(resultMap.get(i));
//            }
//        }


        //todo 从小到大一个个扣的算法
//        Double setPosSubPoint=new Double(needSubPoint);
//        //输多少
//        Long loseNum=this.getPosDict().entrySet().stream().filter(k->k.getValue().getDeductPointYiKao()<0).count();
//        //平均扣分
//        Double avgrPoint=CommMath.div(-setPos.getRoomPos().getGameBeginSportsPoint(),loseNum);
//        List<Integer> losePos=this.getPosDict().entrySet().stream().filter(k->k.getValue().getDeductPointYiKao()<0).
//                sorted(Comparator.comparing(k->-k.getValue().getDeductPointYiKao())).
//                map(k->k.getValue().getPosID()).collect(Collectors.toList());
//        for (int i = 0; i < losePos.size(); i++) {
//            Integer calcPos=losePos.get(i);
//            AbsMJSetPos addPos = this.getPosDict().get(calcPos);
//            //玩家身上扣分
//            Double endPoint = addPos.getDeductPointYiKao();
//            //没有分可以加了
//            if(needSubPoint==0D){
//                break;
//            }
//            //赢的身上不进行补分
//            if(endPoint>0||i==setPos.getPosID()){
//                continue;
//            }
//            //如果输的分数小于分当的平均分 则不考虑
//            if(endPoint>=avgrPoint){
//                continue;
//            }
//            //小于的话 则要进行加分
//            //加的分等于
//            Double needAdd=CommMath.subDouble(avgrPoint,endPoint);
//            //如果超过了 就取剩下的
//            if(needAdd>=needSubPoint){
//                needAdd=needSubPoint;
//            }
//            needSubPoint=CommMath.subDouble(needSubPoint,needAdd);
//            addPos.setDeductPointYiKao(CommMath.addDouble(addPos.getDeductPointYiKao(),needAdd));
//        }
//        //如果有全部扣完 赢的人减去对应的分数
//        if(needSubPoint==0D){
//            setPos.setDeductPointYiKao(CommMath.subDouble(setPos.getDeductPointYiKao(),setPosSubPoint));
//        }

    }

    /**
     * 递归方法
     *
     * @param beginGamePoint
     * @param resultMap
     * @param minValue
     * @return
     */
    private Map<Integer, Double> diGuiMethod(double beginGamePoint, Map<Integer, Double> resultMap, double minValue, double avgrPoint) {
        Long belowZero = resultMap.entrySet().stream().filter(k -> k.getValue() < 0).count();
        boolean allBeolo = resultMap.entrySet().stream().allMatch(k -> k.getValue() >= 0 || (k.getValue() <= avgrPoint));

        if (belowZero.intValue() == 1 || allBeolo) {
            return resultMap;
        }

        for (Map.Entry<Integer, Double> con : resultMap.entrySet()) {
            if (con.getValue() >= 0) {
                continue;
            }
            resultMap.put(con.getKey(), CommMath.addDouble(con.getValue(), Math.abs(minValue)));
            beginGamePoint = CommMath.subDouble(beginGamePoint, Math.abs(minValue));
        }
        Long newPlayerNum = resultMap.entrySet().stream().filter(k -> k.getValue() < 0).count();
        Double newMin = CommMath.div(-beginGamePoint, newPlayerNum.intValue());
        minValue = resultMap.entrySet().stream().filter(k -> k.getValue() > newMin && k.getValue() < 0).
                sorted(Comparator.comparing(k -> -k.getValue())).map(k -> k.getValue()).findFirst().orElse(0D);
        return diGuiMethod(beginGamePoint, resultMap, minValue, newMin);
    }
}
